//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p.gui;

import org.jibble.pircbot.*;
import org.apache.log4j.*;

import ants.p2p.*;
import ants.p2p.irc.*;
import ants.p2p.query.*;
import ants.p2p.utils.addresses.*;

import com.limegroup.gnutella.bootstrap.*;

import java.beans.*;
import java.util.*;

public class ConnectionManager extends Thread implements PropertyChangeListener{
  ConnectionAntPanel cap;

  public static int timeout = 10000;
  public static double freeSlots = 1.0/3.0;

  public static long lastGWebCacheUpdate = 0;
  public static long lastGWebCacheFetch = 0;
  public static boolean publishIpOnGWebCache = false;
  public static boolean searchIpOnGWebCache = true;

  boolean terminate = false;

  static Logger _logger = Logger.getLogger(ConnectionManager.class.getName());

  public ConnectionManager(ConnectionAntPanel cap){
    super();
    this.cap = cap;
    this.setPriority(1);
  }

  public void propertyChange(PropertyChangeEvent e){
    //Nothing
  }

  public void terminate(){
    this.terminate = true;
  }

  public void run(){
    long lastSearchedIrc = 0;
    while (!terminate) {
      try{
        if (publishIpOnGWebCache &&
            (System.currentTimeMillis() - lastGWebCacheUpdate > 65 * 60 * 1000)) {
          BootstrapServerManager.instance().sendUpdatesAsyncV2(new ServerInfo(
              "",
              this.cap.getLocalStringAddress(),
              new Integer(this.cap.getWarriorAnt().getServerPort()), ""));
          lastGWebCacheUpdate = System.currentTimeMillis();
        }
        while (!terminate && cap.warriorAnt.getNeighboursNumber() <
               cap.warriorAnt.getMaxNeighbours() - Math.floor(freeSlots*cap.warriorAnt.getMaxNeighbours()) ) {
          if (this.cap.ircBot != null &&
              this.cap.ircBot.isConnected() &&
              !this.cap.isFirewallChecked() &&
              this.cap.searchPeersOnIRC) {
            try {
              User[] users = cap.ircBot.getUsers(ConnectionAntPanel.ircChannel);
              if (users.length > 1) {
                int userIndex = (int) (Math.random() * users.length);
                while (users[userIndex].equals(ConnectionAntPanel.nick) &&
                       users.length > 1) {
                  userIndex = (int) (Math.random() * users.length);
                }
                cap.ircBot.sendCTCPCommand(users[userIndex].getNick(),
                                           "ANtsCommandCode:0004 " +
                                           FrameAnt.getInstance(null).ga.cap.
                                           getLocalStringAddress() +
                                           ":" +
                                           cap.ircBot.getCaller().warriorAnt.
                                           getServerPort());
                _logger.info("Sent firewall probe message to: " +
                             users[userIndex].getNick());
              }
            }
            catch (Exception ex) {
              _logger.error("IRC Error sending firewall probe message: " +
                            ex.getMessage());
            }
          }
          ArrayList peers = InetAddressEngine.getInstance().getTrustedPeers();
          if (peers.size() > 0) {
            for (int x = 0;
                 x < peers.size() &&
                 cap.warriorAnt.getNeighboursNumber() <
                 cap.warriorAnt.getMaxNeighbours() - Math.floor(freeSlots*cap.warriorAnt.getMaxNeighbours()); x++) {
              ServerInfo peer = (ServerInfo) peers.get(x);
              if (! (peer.getAddress().getHostAddress().equals(this.cap.
                  getLocalInetAddress().getHostAddress()) &&
                     peer.getPort().intValue() ==
                     this.cap.warriorAnt.getServerPort())) {
                _logger.info("Trying retrieving peers info from: " +
                             ( (ServerInfo) peers.get(x)).
                             getAddress().
                             getHostAddress() + ":" +
                             ( ( (ServerInfo) peers.get(x)).getPort().
                              intValue()));

                ServerInfo sInfos = (ServerInfo) peers.get(x);
                cap.jTextField5.setText(sInfos.getAddress().getHostAddress());
                cap.jTextField6.setText( (sInfos.getPort().intValue() ) + "");
                RefreshAndConnectThread refreshAndConnectThread = new
                    RefreshAndConnectThread(this.cap);
                refreshAndConnectThread.start();
                refreshAndConnectThread.join();
              }
            }
          }
          peers = InetAddressEngine.getRandomPeersWithFreeSlots(InetAddressEngine.peersToSendback, false);
          _logger.info("Looking for peers!!!"+peers.size());
          if (peers.size() > 0) {
            for (int x = 0;
                 x < peers.size() &&
                 cap.warriorAnt.getNeighboursNumber() <
                 cap.warriorAnt.getMaxNeighbours() - Math.floor(freeSlots*cap.warriorAnt.getMaxNeighbours()); x++) {
              ServerInfo peer = (ServerInfo) peers.get(x);
              if (! (peer.getAddress().getHostAddress().equals(this.cap.
                  getLocalInetAddress().getHostAddress()) &&
                     peer.getPort().intValue() ==
                     this.cap.warriorAnt.getServerPort())) {
                _logger.info("Trying retrieving peers info from: " +
                             ( (ServerInfo) peers.get(x)).
                             getAddress().
                             getHostAddress() + ":" +
                             ( ( (ServerInfo) peers.get(x)).getPort().
                              intValue()));
                ServerInfo sInfos = (ServerInfo) peers.get(x);
                cap.jTextField5.setText(sInfos.getAddress().getHostAddress());
                cap.jTextField6.setText( (sInfos.getPort().intValue() ) + "");
                RefreshAndConnectThread refreshAndConnectThread = new
                    RefreshAndConnectThread(this.cap);
                refreshAndConnectThread.start();
                refreshAndConnectThread.join();
              }else{

              }
            }
          }else{
            lastGWebCacheFetch = 0;
          }
          peers = InetAddressEngine.getRandomIMPeersWithFreeSlots(InetAddressEngine.peersToSendback);
          if (peers.size() > 0) {
            for (int x = 0;
                 x < peers.size() &&
                 cap.warriorAnt.getNeighboursNumber() <
                 cap.warriorAnt.getMaxNeighbours() - Math.floor(freeSlots*cap.warriorAnt.getMaxNeighbours()); x++) {
              ServerInfo peer = (ServerInfo) peers.get(x);
              if (! (peer.getAddress().getHostAddress().equals(this.cap.
                  getLocalInetAddress().getHostAddress()) &&
                     peer.getPort().intValue() ==
                     this.cap.warriorAnt.getServerPort())) {
                _logger.info("Trying retrieving peers info from: " +
                             ( (ServerInfo) peers.get(x)).
                             getAddress().
                             getHostAddress() + ":" +
                             ( ( (ServerInfo) peers.get(x)).getPort().
                              intValue()));

                ServerInfo sInfos = (ServerInfo) peers.get(x);
                cap.jTextField5.setText(sInfos.getAddress().getHostAddress());
                cap.jTextField6.setText( (sInfos.getPort().intValue() ) + "");
                RefreshAndConnectThread refreshAndConnectThread = new
                    RefreshAndConnectThread(this.cap);
                refreshAndConnectThread.start();
                refreshAndConnectThread.join();
              }
            }
          }
          if(searchIpOnGWebCache &&
             (System.currentTimeMillis() - lastGWebCacheFetch > 65*60*1000)){
            BootstrapServerManager.instance().resetData();
            BootstrapServerManager.instance().fetchEndpointsAsyncV2();
            lastGWebCacheFetch=System.currentTimeMillis();
          }
          if(publishIpOnGWebCache &&
             (System.currentTimeMillis() - lastGWebCacheUpdate > 65*60*1000)){
            BootstrapServerManager.instance().sendUpdatesAsyncV2(new ServerInfo("",
                this.cap.getLocalStringAddress(),
                new Integer(this.cap.getWarriorAnt().getServerPort()),""));
            lastGWebCacheUpdate = System.currentTimeMillis();
          }
          if (this.cap.ircBot != null &&
              this.cap.ircBot.isConnected() &&
              this.cap.searchPeersOnIRC &&
              cap.warriorAnt.getNeighboursNumber() <
              cap.warriorAnt.getMaxNeighbours() - Math.floor(freeSlots*cap.warriorAnt.getMaxNeighbours()) &&
              System.currentTimeMillis() - lastSearchedIrc > timeout) {
            try {
              lastSearchedIrc = System.currentTimeMillis();
              User[] users = cap.ircBot.getUsers(ConnectionAntPanel.ircChannel); //this.ircBot.getActiveChannel());
              if (users.length > 1) {
                int userIndex = (int) (Math.random() * users.length);
                while (users[userIndex].equals(ConnectionAntPanel.nick) &&
                       users.length > 1) {
                  userIndex = (int) (Math.random() * users.length);
                }
                cap.ircBot.sendCTCPCommand(users[userIndex].getNick(),
                                       "ANtsCommandCode:0003");
                _logger.info("Sent request message to: " +
                             users[userIndex].getNick());
              }
            }
            catch (Exception ex) {
              _logger.error("IRC Client Error: " + ex.getMessage());
            }
          }
          try {
            if (cap.warriorAnt.getNeighboursNumber() > cap.warriorAnt.getMaxNeighbours() * 2.0 / 3.0)
              sleep(timeout * cap.warriorAnt.getNeighboursNumber());
            else
              sleep(timeout);
          }
          catch (Exception e) {
            _logger.error("Connection manager sleep Exception: " + e.getMessage());
          }
        }
        try {
          if (cap.warriorAnt.getNeighboursNumber() > cap.warriorAnt.getMaxNeighbours() * 2.0 / 3.0)
            sleep(timeout * cap.warriorAnt.getNeighboursNumber());
          else
            sleep(timeout);
        }
        catch (Exception e) {
          _logger.error("Connection manager sleep Exception: " + e.getMessage());
        }
      }
      catch (Exception e) {
        _logger.error("Connection manager main cycle error", e);
        try {
          if (cap.warriorAnt.getNeighboursNumber() > cap.warriorAnt.getMaxNeighbours() * 2.0 / 3.0)
            sleep(timeout * cap.warriorAnt.getNeighboursNumber());
          else
            sleep(timeout);
        }
        catch (Exception ex) {
          _logger.error("Connection manager sleep Exception: " + ex.getMessage());
        }
      }
    }
  }
}
